From c996af342de29015925decdf95335415381475f7 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Tue, 24 Jan 2006 03:35:53 +0000 Subject: [PATCH] Add GtkLinkButton, a port of GnomeHRef. (#314808, Emmanuele Bassi) 2006-01-23 Matthias Clasen Add GtkLinkButton, a port of GnomeHRef. (#314808, Emmanuele Bassi) * gtk/gtklinkbutton.h: * gtk/gtklinkbutton.c: New files. * gtk/gtk.h: * gtk/gtk.symbols: * gtk/Makefile.am: Glue. * gtk/gtkaboutdialog.c: Use GtkLinkButton. --- ChangeLog | 11 + ChangeLog.pre-2-10 | 11 + gtk/Makefile.am | 2 + gtk/gtk.h | 1 + gtk/gtk.symbols | 10 + gtk/gtkaboutdialog.c | 99 +------ gtk/gtklinkbutton.c | 619 +++++++++++++++++++++++++++++++++++++++++++ gtk/gtklinkbutton.h | 73 +++++ 8 files changed, 734 insertions(+), 92 deletions(-) create mode 100644 gtk/gtklinkbutton.c create mode 100644 gtk/gtklinkbutton.h diff --git a/ChangeLog b/ChangeLog index 982c3ee737..f55fd082e6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,16 @@ 2006-01-23 Matthias Clasen + Add GtkLinkButton, a port of GnomeHRef. (#314808, Emmanuele Bassi) + + * gtk/gtklinkbutton.h: + * gtk/gtklinkbutton.c: New files. + + * gtk/gtk.h: + * gtk/gtk.symbols: + * gtk/Makefile.am: Glue. + + * gtk/gtkaboutdialog.c: Use GtkLinkButton. + * gtk/gtkwidget.c: Add link-color and visited-link-color style properties. (#113649, Leena Gunda) diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 982c3ee737..f55fd082e6 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,5 +1,16 @@ 2006-01-23 Matthias Clasen + Add GtkLinkButton, a port of GnomeHRef. (#314808, Emmanuele Bassi) + + * gtk/gtklinkbutton.h: + * gtk/gtklinkbutton.c: New files. + + * gtk/gtk.h: + * gtk/gtk.symbols: + * gtk/Makefile.am: Glue. + + * gtk/gtkaboutdialog.c: Use GtkLinkButton. + * gtk/gtkwidget.c: Add link-color and visited-link-color style properties. (#113649, Leena Gunda) diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 1490df4a19..6a4d5b6558 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -198,6 +198,7 @@ gtk_public_h_sources = \ gtkitemfactory.h \ gtklabel.h \ gtklayout.h \ + gtklinkbutton.h \ gtklist.h \ gtklistitem.h \ gtkliststore.h \ @@ -423,6 +424,7 @@ gtk_c_sources = \ gtkkeyhash.h \ gtklabel.c \ gtklayout.c \ + gtklinkbutton.c \ gtklist.c \ gtklistitem.c \ gtkliststore.c \ diff --git a/gtk/gtk.h b/gtk/gtk.h index ec1bf6061a..f7bad3354d 100644 --- a/gtk/gtk.h +++ b/gtk/gtk.h @@ -110,6 +110,7 @@ #include #include #include +#include #include #include #include diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols index 5d74f35dab..395df2ea5a 100644 --- a/gtk/gtk.symbols +++ b/gtk/gtk.symbols @@ -1994,6 +1994,16 @@ gtk_layout_thaw #endif #endif +#if IN_HEADER(__GTK_LINK_BUTTON_H__) +#if IN_FILE(__GTK_LINK_BUTTON_C__) +gtk_link_button_get_type G_GNUC_CONST +gtk_link_button_new +gtk_link_button_new_with_label +gtk_link_button_get_uri +gtk_link_button_set_uri +#endif +#endif + #if IN_HEADER(__GTK_LIST_H__) #if IN_FILE(__GTK_LIST_C__) gtk_list_append_items diff --git a/gtk/gtkaboutdialog.c b/gtk/gtkaboutdialog.c index 1a80c214c2..c360449bab 100644 --- a/gtk/gtkaboutdialog.c +++ b/gtk/gtkaboutdialog.c @@ -39,6 +39,7 @@ #include "gtkhbox.h" #include "gtkimage.h" #include "gtklabel.h" +#include "gtklinkbutton.h" #include "gtkmarshalers.h" #include "gtknotebook.h" #include "gtkscrolledwindow.h" @@ -133,14 +134,6 @@ static void update_name_version (GtkAboutDialog static GtkIconSet * icon_set_new_from_pixbufs (GList *pixbufs); static void activate_url (GtkWidget *widget, gpointer data); -static void set_link_button_text (GtkWidget *about, - GtkWidget *button, - gchar *text); -static GtkWidget * create_link_button (GtkWidget *about, - gchar *text, - gchar *url, - GCallback callback, - gpointer data); static void follow_if_link (GtkAboutDialog *about, GtkTextView *text_view, GtkTextIter *iter); @@ -486,8 +479,9 @@ gtk_about_dialog_init (GtkAboutDialog *about) gtk_label_set_justify (GTK_LABEL (priv->copyright_label), GTK_JUSTIFY_CENTER); gtk_box_pack_start (GTK_BOX (vbox), priv->copyright_label, FALSE, FALSE, 0); - button = create_link_button (GTK_WIDGET (about), "", "", - G_CALLBACK (activate_url), about); + button = gtk_link_button_new (""); + g_signal_connect (G_OBJECT (button), "clicked", + G_CALLBACK (activate_url), about); hbox = gtk_hbox_new (TRUE, 0); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); @@ -1141,9 +1135,7 @@ gtk_about_dialog_set_website (GtkAboutDialog *about, priv->website = g_strdup (website); if (activate_url_hook != NULL) { - g_object_set_data_full (G_OBJECT (priv->website_button), - I_("url"), - g_strdup (website), g_free); + gtk_link_button_set_uri (GTK_LINK_BUTTON (priv->website_button), website); if (priv->website_label == NULL) gtk_about_dialog_set_website_label (about, website); } @@ -1160,8 +1152,6 @@ gtk_about_dialog_set_website (GtkAboutDialog *about, else { priv->website = NULL; - g_object_set_data (G_OBJECT (priv->website_button), - I_("url"), NULL); gtk_widget_hide (priv->website_button); } g_free (tmp); @@ -1219,8 +1209,7 @@ gtk_about_dialog_set_website_label (GtkAboutDialog *about, if (website_label != NULL) { priv->website_label = g_strdup (website_label); - set_link_button_text (GTK_WIDGET (about), - priv->website_button, + gtk_button_set_label (GTK_BUTTON (priv->website_button), priv->website_label); gtk_widget_show (priv->website_button); } @@ -1632,86 +1621,12 @@ activate_url (GtkWidget *widget, gpointer data) { GtkAboutDialog *about = GTK_ABOUT_DIALOG (data); - gchar *url = g_object_get_data (G_OBJECT (widget), "url"); + gchar *url = gtk_link_button_get_uri (GTK_LINK_BUTTON (widget)); if (activate_url_hook != NULL) (* activate_url_hook) (about, url, activate_url_hook_data); } -static void -set_link_button_text (GtkWidget *about, - GtkWidget *button, - gchar *text) -{ - GtkWidget *label; - gchar *link; - GdkColor *style_link_color; - GdkColor link_color = { 0, 0, 0, 0xeeee }; - - gtk_widget_ensure_style (about); - gtk_widget_style_get (about, "link-color", &style_link_color, NULL); - if (style_link_color) - { - link_color = *style_link_color; - gdk_color_free (style_link_color); - } - - link = g_markup_printf_escaped ("%s", - link_color.red, link_color.green, link_color.blue, text); - - label = gtk_bin_get_child (GTK_BIN (button)); - gtk_label_set_markup (GTK_LABEL (label), link); - g_free (link); -} - -static gboolean -link_button_enter (GtkWidget *widget, - GdkEventCrossing *event, - GtkAboutDialog *about) -{ - GtkAboutDialogPrivate *priv = (GtkAboutDialogPrivate *)about->private_data; - gdk_window_set_cursor (widget->window, priv->hand_cursor); - - return FALSE; -} - -static gboolean -link_button_leave (GtkWidget *widget, - GdkEventCrossing *event, - GtkAboutDialog *about) -{ - gdk_window_set_cursor (widget->window, NULL); - - return FALSE; -} - -static GtkWidget * -create_link_button (GtkWidget *about, - gchar *text, - gchar *url, - GCallback callback, - gpointer data) -{ - GtkWidget *button; - - button = gtk_button_new_with_label (""); - GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT); - gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); - - g_object_set_data_full (G_OBJECT (button), - I_("url"), - g_strdup (url), g_free); - set_link_button_text (about, button, text); - - g_signal_connect (button, "clicked", callback, data); - g_signal_connect (button, "enter_notify_event", - G_CALLBACK (link_button_enter), data); - g_signal_connect (button, "leave_notify_event", - G_CALLBACK (link_button_leave), data); - - return button; -} - static void follow_if_link (GtkAboutDialog *about, GtkTextView *text_view, diff --git a/gtk/gtklinkbutton.c b/gtk/gtklinkbutton.c new file mode 100644 index 0000000000..8bae769dc1 --- /dev/null +++ b/gtk/gtklinkbutton.c @@ -0,0 +1,619 @@ +/* GTK - The GIMP Toolkit + * gtklinkbutton.c - an hyperlink-enabled button + * + * Copyright (C) 2006 Emmanuele Bassi + * All rights reserved. + * + * Based on gnome-href code by: + * James Henstridge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Cambridge, MA 02139, USA. + */ + +#include "config.h" + +#include + +#include +#include +#include + +#include "gtkclipboard.h" +#include "gtkdnd.h" +#include "gtkimagemenuitem.h" +#include "gtklabel.h" +#include "gtkmain.h" +#include "gtkmenu.h" +#include "gtkmenuitem.h" +#include "gtkstock.h" + +#include "gtklinkbutton.h" + +#include "gtkintl.h" +#include "gtkalias.h" + + +struct _GtkLinkButtonPrivate +{ + gchar *uri; + + gboolean visited; + + GtkWidget *popup_menu; +}; + +enum +{ + PROP_0, + + PROP_URI, +}; + +#define GTK_LINK_BUTTON_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_LINK_BUTTON, GtkLinkButtonPrivate)) + +static void gtk_link_button_finalize (GObject *object); +static void gtk_link_button_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void gtk_link_button_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_link_button_add (GtkContainer *container, + GtkWidget *widget); +static gboolean gtk_link_button_button_press (GtkWidget *widget, + GdkEventButton *event); +static void gtk_link_button_clicked (GtkButton *button); +static gboolean gtk_link_button_popup_menu (GtkWidget *widget); +static void gtk_link_button_style_set (GtkWidget *widget, + GtkStyle *old_style); +static gboolean gtk_link_button_enter_cb (GtkWidget *widget, + GdkEventCrossing *event, + gpointer user_data); +static gboolean gtk_link_button_leave_cb (GtkWidget *widget, + GdkEventCrossing *event, + gpointer user_data); +static void gtk_link_button_drag_data_get_cb (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection, + guint _info, + guint _time, + gpointer user_data); + + +static const GtkTargetEntry link_drop_types[] = { + { "text/uri-list", 0, 0 }, + { "_NETSCAPE_URL", 0, 0 } +}; + +static GdkColor default_link_color = { 0, 0, 0, 0xeeee }; +static GdkColor default_visited_link_color = { 0, 0x5555, 0x1a1a, 0x8b8b }; + +G_DEFINE_TYPE (GtkLinkButton, gtk_link_button, GTK_TYPE_BUTTON); + +static void +gtk_link_button_class_init (GtkLinkButtonClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GtkContainerClass *container_class = GTK_WIDGET_CLASS (klass); + GtkButtonClass *button_class = GTK_BUTTON_CLASS (klass); + + gobject_class->set_property = gtk_link_button_set_property; + gobject_class->get_property = gtk_link_button_get_property; + gobject_class->finalize = gtk_link_button_finalize; + + widget_class->button_press_event = gtk_link_button_button_press; + widget_class->popup_menu = gtk_link_button_popup_menu; + widget_class->style_set = gtk_link_button_style_set; + + container_class->add = gtk_link_button_add; + + button_class->clicked = gtk_link_button_clicked; + + /** + * GtkLinkButton:uri + * + * The URI bound to this button. + * + * Since: 2.10 + */ + g_object_class_install_property (gobject_class, + PROP_URI, + g_param_spec_string ("uri", + _("URI"), + _("The URI bound to this button"), + "http://www.gtk.org", + G_PARAM_READWRITE)); + + g_type_class_add_private (gobject_class, sizeof (GtkLinkButtonPrivate)); +} + +static void +gtk_link_button_init (GtkLinkButton *link_button) +{ + link_button->priv = GTK_LINK_BUTTON_GET_PRIVATE (link_button), + + gtk_button_set_relief (GTK_BUTTON (link_button), GTK_RELIEF_NONE); + + g_signal_connect (link_button, "enter-notify-event", + G_CALLBACK (gtk_link_button_enter_cb), NULL); + g_signal_connect (link_button, "leave-notify-event", + G_CALLBACK (gtk_link_button_leave_cb), NULL); + g_signal_connect (link_button, "drag-data-get", + G_CALLBACK (gtk_link_button_drag_data_get_cb), NULL); + + /* enable drag source */ + gtk_drag_source_set (GTK_WIDGET (link_button), + GDK_BUTTON1_MASK, + link_drop_types, G_N_ELEMENTS (link_drop_types), + GDK_ACTION_COPY); +} + +static void +gtk_link_button_finalize (GObject *object) +{ + GtkLinkButton *link_button = GTK_LINK_BUTTON (object); + + g_free (link_button->priv->uri); + + G_OBJECT_CLASS (gtk_link_button_parent_class)->finalize (object); +} + +static void +gtk_link_button_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkLinkButton *link_button = GTK_LINK_BUTTON (object); + + switch (prop_id) + { + case PROP_URI: + g_value_set_string (value, link_button->priv->uri); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_link_button_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkLinkButton *link_button = GTK_LINK_BUTTON (object); + + switch (prop_id) + { + case PROP_URI: + gtk_link_button_set_uri (link_button, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_link_color (GtkLinkButton *link_button) +{ + GdkColor *link_color = NULL; + GtkWidget *label; + + label = gtk_bin_get_child (GTK_BIN (link_button)); + + if (link_button->priv->visited) + { + gtk_widget_style_get (GTK_WIDGET (link_button), + "visited-link-color", &link_color, NULL); + if (!link_color) + link_color = &default_visited_link_color; + } + else + { + gtk_widget_style_get (GTK_WIDGET (link_button), + "link-color", &link_color, NULL); + if (!link_color) + link_color = &default_link_color; + } + + gtk_widget_modify_fg (label, GTK_STATE_NORMAL, link_color); + gtk_widget_modify_fg (label, GTK_STATE_ACTIVE, link_color); + gtk_widget_modify_fg (label, GTK_STATE_PRELIGHT, link_color); + gtk_widget_modify_fg (label, GTK_STATE_SELECTED, link_color); + + if (link_color != &default_link_color && + link_color != &default_visited_link_color) + gdk_color_free (link_color); +} + +static void +set_link_underline (GtkLinkButton *link_button) +{ + GtkWidget *label; + + label = gtk_bin_get_child (GTK_BIN (link_button)); + if (GTK_IS_LABEL (label)) + { + PangoAttrList *attributes; + PangoAttribute *uline; + + uline = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE); + uline->start_index = 0; + uline->end_index = G_MAXUINT; + attributes = pango_attr_list_new (); + pango_attr_list_insert (attributes, uline); + gtk_label_set_attributes (GTK_LABEL (label), attributes); + } +} + +static void +gtk_link_button_add (GtkContainer *container, + GtkWidget *widget) +{ + GTK_CONTAINER_CLASS (gtk_link_button_parent_class)->add (container, widget); + + set_link_underline (GTK_LINK_BUTTON (container)); +} + +static void +gtk_link_button_style_set (GtkWidget *widget, + GtkStyle *old_style) +{ + GtkLinkButton *link_button = GTK_LINK_BUTTON (widget); + + set_link_color (link_button); +} + +static void +set_hand_cursor (GtkWidget *widget, + gboolean show_hand) +{ + GdkDisplay *display; + GdkCursor *cursor; + + display = gtk_widget_get_display (widget); + + cursor = NULL; + if (show_hand) + cursor = gdk_cursor_new_for_display (display, GDK_HAND2); + + gdk_window_set_cursor (widget->window, cursor); + gdk_display_flush (display); + + if (cursor) + gdk_cursor_unref (cursor); +} + +static void +popup_menu_detach (GtkWidget *attach_widget, + GtkMenu *menu) +{ + GtkLinkButton *link_button = GTK_LINK_BUTTON (attach_widget); + + link_button->priv->popup_menu = NULL; +} + +static void +popup_position_func (GtkMenu *menu, + gint *x, + gint *y, + gboolean *push_in, + gpointer user_data) +{ + GtkLinkButton *link_button = GTK_LINK_BUTTON (user_data); + GtkLinkButtonPrivate *priv = link_button->priv; + GtkWidget *widget = GTK_WIDGET (link_button); + GdkScreen *screen = gtk_widget_get_screen (widget); + GtkRequisition req; + gint monitor_num; + GdkRectangle monitor; + + g_return_if_fail (GTK_WIDGET_REALIZED (link_button)); + + gdk_window_get_origin (widget->window, x, y); + + gtk_widget_size_request (priv->popup_menu, &req); + + *x += widget->allocation.width / 2; + *y += widget->allocation.height; + + monitor_num = gdk_screen_get_monitor_at_point (screen, *x, *y); + gtk_menu_set_monitor (menu, monitor_num); + gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); + + *x = CLAMP (*x, monitor.x, monitor.x + MAX (0, monitor.width - req.width)); + *y = CLAMP (*y, monitor.y, monitor.y + MAX (0, monitor.height - req.height)); + + *push_in = FALSE; +} + +static void +copy_activate_cb (GtkWidget *widget, + GtkLinkButton *link_button) +{ + GtkLinkButtonPrivate *priv = link_button->priv; + + gtk_clipboard_set_text (gtk_widget_get_clipboard (GTK_WIDGET (link_button), + GDK_SELECTION_CLIPBOARD), + priv->uri, -1); +} + +static void +gtk_link_button_do_popup (GtkLinkButton *link_button, + GdkEventButton *event) +{ + GtkLinkButtonPrivate *priv = link_button->priv; + gint button; + guint time; + + if (event) + { + button = event->button; + time = event->time; + } + else + { + button = 0; + time = gtk_get_current_event_time (); + } + + if (GTK_WIDGET_REALIZED (link_button)) + { + GtkWidget *menu_item; + + if (priv->popup_menu) + gtk_widget_destroy (priv->popup_menu); + + priv->popup_menu = gtk_menu_new (); + + gtk_menu_attach_to_widget (GTK_MENU (priv->popup_menu), + GTK_WIDGET (link_button), + popup_menu_detach); + + menu_item = gtk_image_menu_item_new_with_mnemonic (_("Copy URL")); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), + gtk_image_new_from_stock (GTK_STOCK_COPY, + GTK_ICON_SIZE_MENU)); + g_signal_connect (menu_item, "activate", + G_CALLBACK (copy_activate_cb), link_button); + gtk_widget_show (menu_item); + gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menu_item); + + if (button) + gtk_menu_popup (GTK_MENU (priv->popup_menu), NULL, NULL, + NULL, NULL, + button, time); + else + { + gtk_menu_popup (GTK_MENU (priv->popup_menu), NULL, NULL, + popup_position_func, link_button, + button, time); + gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->popup_menu), FALSE); + } + } +} + +static gboolean +gtk_link_button_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + if (!GTK_WIDGET_HAS_FOCUS (widget)) + gtk_widget_grab_focus (widget); + + if ((event->button == 3) && (event->type == GDK_BUTTON_PRESS)) + { + gtk_link_button_do_popup (GTK_LINK_BUTTON (widget), event); + + return TRUE; + } + + if (GTK_WIDGET_CLASS (gtk_link_button_parent_class)->button_press_event) + return (* GTK_WIDGET_CLASS (gtk_link_button_parent_class)->button_press_event) (widget, event); + + return FALSE; +} + +static void +gtk_link_button_clicked (GtkButton *button) +{ + GtkLinkButton *link_button = GTK_LINK_BUTTON (button); + + link_button->priv->visited = TRUE; + + set_link_color (link_button); +} + +static gboolean +gtk_link_button_popup_menu (GtkWidget *widget) +{ + gtk_link_button_do_popup (GTK_LINK_BUTTON (widget), NULL); + + return TRUE; +} + +static gboolean +gtk_link_button_enter_cb (GtkWidget *widget, + GdkEventCrossing *crossing, + gpointer user_data) +{ + set_hand_cursor (widget, TRUE); + + return FALSE; +} + +static gboolean +gtk_link_button_leave_cb (GtkWidget *widget, + GdkEventCrossing *crossing, + gpointer user_data) +{ + set_hand_cursor (widget, FALSE); + + return FALSE; +} + +static void +gtk_link_button_drag_data_get_cb (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection, + guint _info, + guint _time, + gpointer user_data) +{ + GtkLinkButton *link_button = GTK_LINK_BUTTON (widget); + gchar *uri; + + uri = g_strdup_printf ("%s\r\n", link_button->priv->uri); + gtk_selection_data_set (selection, + selection->target, + 8, + (guchar *) uri, + strlen (uri)); + + g_free (uri); +} + +/** + * gtk_link_button_new: + * @uri: a valid URI + * + * Creates a new #GtkLinkButton with the URI as its text. + * + * Return value: a new link button widget. + * + * Since: 2.10 + */ +GtkWidget * +gtk_link_button_new (const gchar *uri) +{ + gchar *utf8_uri = NULL; + GtkWidget *retval; + + g_return_val_if_fail (uri != NULL, NULL); + + if (g_utf8_validate (uri, -1, NULL)) + { + utf8_uri = g_strdup (uri); + } + else + { + GError *conv_err = NULL; + + utf8_uri = g_locale_to_utf8 (uri, -1, NULL, NULL, &conv_err); + if (conv_err) + { + g_warning ("Attempting to convert URI `%s' to UTF-8, but failed " + "with error: %s\n", + uri, + conv_err->message); + g_error_free (conv_err); + + utf8_uri = g_strdup (_("Invalid URI")); + } + } + + retval = g_object_new (GTK_TYPE_LINK_BUTTON, + "uri", uri, + "label", utf8_uri, + NULL); + + g_free (utf8_uri); + + return retval; +} + +/** + * gtk_link_button_new_with_label: + * @uri: a valid URI + * @label: the text of the button + * + * Creates a new #GtkLinkButton containing a label. + * + * Return value: a new link button widget. + * + * Since: 2.10 + */ +GtkWidget * +gtk_link_button_new_with_label (const gchar *uri, + const gchar *label) +{ + GtkWidget *retval; + + g_return_val_if_fail (uri != NULL, FALSE); + + if (!label) + return gtk_link_button_new (uri); + + retval = g_object_new (GTK_TYPE_LINK_BUTTON, + "label", label, + "uri", uri, + NULL); + + return retval; +} + +/** + * gtk_link_button_set_uri: + * @link_button: a #GtkLinkButton + * @uri: a valid URI + * + * Sets @uri as the URI where the #GtkLinkButton points. + * + * Since: 2.10 + */ +void +gtk_link_button_set_uri (GtkLinkButton *link_button, + const gchar *uri) +{ + gchar *tmp; + + g_return_if_fail (GTK_IS_LINK_BUTTON (link_button)); + g_return_if_fail (uri != NULL); + + tmp = link_button->priv->uri; + link_button->priv->uri = g_strdup (uri); + g_free (tmp); + + link_button->priv->visited = FALSE; + + g_object_notify (G_OBJECT (link_button), "uri"); +} + +/** + * gtk_link_button_get_uri: + * @link_button: a #GtkLinkButton + * + * Retrieves the URI set using gtk_link_button_set_uri(). + * + * Return value: a valid URI. The returned string is owned by the link button + * and should not be modified or freed. + * + * Since: 2.10 + */ +G_CONST_RETURN gchar * +gtk_link_button_get_uri (GtkLinkButton *link_button) +{ + g_return_val_if_fail (GTK_IS_LINK_BUTTON (link_button), NULL); + + return link_button->priv->uri; +} + +#define __GTK_LINK_BUTTON_C__ +#include "gtkaliasdef.c" diff --git a/gtk/gtklinkbutton.h b/gtk/gtklinkbutton.h new file mode 100644 index 0000000000..25affc7e71 --- /dev/null +++ b/gtk/gtklinkbutton.h @@ -0,0 +1,73 @@ +/* GTK - The GIMP Toolkit + * gtklinkbutton.h - an hyperlink-enabled button + * + * Copyright (C) 2005 Emmanuele Bassi + * All rights reserved. + * + * Based on gnome-href code by: + * James Henstridge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Cambridge, MA 02139, USA. + */ + +#ifndef __GTK_LINK_BUTTON_H__ +#define __GTK_LINK_BUTTON_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_LINK_BUTTON (gtk_link_button_get_type ()) +#define GTK_LINK_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_LINK_BUTTON, GtkLinkButton)) +#define GTK_IS_LINK_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_LINK_BUTTON)) +#define GTK_LINK_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_LINK_BUTTON, GtkLinkButtonClass)) +#define GTK_IS_LINK_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_LINK_BUTTON)) +#define GTK_LINK_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_LINK_BUTTON, GtkLinkButtonClass)) + +typedef struct _GtkLinkButton GtkLinkButton; +typedef struct _GtkLinkButtonClass GtkLinkButtonClass; +typedef struct _GtkLinkButtonPrivate GtkLinkButtonPrivate; + +struct _GtkLinkButton +{ + GtkButton parent_instance; + + GtkLinkButtonPrivate *priv; +}; + +struct _GtkLinkButtonClass +{ + GtkButtonClass parent_class; + + void (*_gtk_padding1) (void); + void (*_gtk_padding2) (void); + void (*_gtk_padding3) (void); + void (*_gtk_padding4) (void); +}; + +GType gtk_link_button_get_type (void) G_GNUC_CONST; + +GtkWidget * gtk_link_button_new (const gchar *uri); +GtkWidget * gtk_link_button_new_with_label (const gchar *uri, + const gchar *label); + +G_CONST_RETURN gchar *gtk_link_button_get_uri (GtkLinkButton *link_button); +void gtk_link_button_set_uri (GtkLinkButton *link_button, + const gchar *uri); + +G_END_DECLS + +#endif /* __GTK_LINK_BUTTON_H__ */ -- 2.30.2